module ("TweenSys", package.seeall)
---	EFL: EasingForLua - Easing Functions Library for Lua
--- Copyright (C) 2011.
---	Written by Roland Yonaba - E-mail: roland[dot]yonaba[at]gmail[dot]com
---	EFL is a package of Easing functions for Lua
---
---	Credits to : Robert Penner Easing Equations [http://www.robertpenner.com/easing]
---				 Yuichi Tateno [http://coderepos.org/share/wiki/JSTweener]
---				 Kikito (github.com/kikito/easing ,  github.com/kikito/tween.lua)
---
--- Note : All Easing functions are composed of 4 types of easing
---
---	IN-EASING: Meaning that the easing effect will be applied at the start of the motion
---	OUT-EASING: Meaning that the easing effect will be applied at the end of the motion
---	OUTIN-EASING: Meaning that the easing effect will be applied at the start and the end of the motion
---	INOUT-EASING: Meaning that the easing effect will be applied at the middle of the motion



--- This is a example easing function
--- parameters showed here include all the possible situation
-- @param t time
-- @param b begin
-- @param c change in position
-- @param d duration of the tween effect
-- @param s step (Optional - only required for Back easing)
-- @param a amplitude (Optional - only required for Elastic Easing)
-- @param p period (Optional - only required for Elastic Easing)
local function EasingFunctionName(t,b,c,d,s,a,p)
end

----------- LINEAR EASING --------
local function LINEAR(t, b, c, d)
  return c * t / d + b
end

----------- QUADRATIC EASING --------
local function INQUAD(t, b, c, d)
  local t = t / d
  return c * math.pow(t, 2) + b
end

local function OUTQUAD(t, b, c, d)
  local t = t / d
  return -c * t * (t - 2) + b
end

local function INOUTQUAD(t, b, c, d)
  local t = t / d * 2
  if t < 1 then
    return c / 2 * math.pow(t, 2) + b
  else
    return -c / 2 * ((t - 1) * (t - 3) - 1) + b
  end
end

----------- CUBIC EASING --------
local function INCUBIC (t, b, c, d)
  local t = t / d
  return c * math.pow(t, 3) + b
end

local function OUTCUBIC(t, b, c, d)
  local t = t / d - 1
  return c * (math.pow(t, 3) + 1) + b
end

local function INOUTCUBIC(t, b, c, d)
  local t = t / d * 2
  if t < 1 then
    return c / 2 * t * t * t + b
  else
    t = t - 2
    return c / 2 * (t * t * t + 2) + b
  end
end

local function OUTINCUBIC(t, b, c, d)
  if t < d / 2 then
    return OUTCUBIC(t * 2, b, c / 2, d)
  else
    return INCUBIC((t * 2) - d, b + c / 2, c / 2, d)
  end
end

----------- QUARTIC EASING --------
local function INQUART(t, b, c, d)
  local t = t / d
  return c * math.pow(t, 4) + b
end

local function OUTQUART(t, b, c, d)
  local t = t / d - 1
  return -c * (math.pow(t, 4) - 1) + b
end

local function INOUTQUUART(t, b, c, d)
  local t = t / d * 2
  if t < 1 then
    return c / 2 * math.pow(t, 4) + b
  else
    t = t - 2
    return -c / 2 * (math.pow(t, 4) - 2) + b
  end
end

local function OUTINQUART(t, b, c, d)
  if t < d / 2 then
    return OUTQUART(t * 2, b, c / 2, d)
  else
    return INQUART((t * 2) - d, b + c / 2, c / 2, d)
  end
end

----------- QUINTIC EASING --------
local function INQUINT(t, b, c, d)
  local t = t / d
  return c * math.pow(t, 5) + b
end

local function OUTQUINT(t, b, c, d)
  local t = t / d - 1
  return c * (math.pow(t, 5) + 1) + b
end

local function INOUTQUINT(t, b, c, d)
  local t = t / d * 2
  if t < 1 then
    return c / 2 * math.pow(t, 5) + b
  else
    t = t - 2
    return c / 2 * (math.pow(t, 5) + 2) + b
  end
end

local function OUTINQUINT(t, b, c, d)
  if t < d / 2 then
    return OUTQUINT(t * 2, b, c / 2, d)
  else
    return INQUINT((t * 2) - d, b + c / 2, c / 2, d)
  end
end

----------- SINUSOIDAL EASING --------
local function INSINE(t, b, c, d)
  return -c * math.cos(t / d * (math.pi / 2)) + c + b
end

local function OUTSINE(t, b, c, d)
  return c * math.sin(t / d * (math.pi / 2)) + b
end

local function INOUTSINE(t, b, c, d)
  return -c / 2 * (math.cos(math.pi * t / d) - 1) + b
end

local function OUTINSINE(t, b, c, d)
  if t < d / 2 then
    return OUTSINE(t * 2, b, c / 2, d)
  else
    return INSINE((t * 2) -d, b + c / 2, c / 2, d)
  end
end

----------- EXPONENTIAL EASING --------
local function INEXP(t, b, c, d)
  if t == 0 then
    return b
  else
    return c * math.pow(2, 10 * (t / d - 1)) + b - c * 0.001
  end
end

local function OUTEXP(t, b, c, d)
  if t == d then
    return b + c
  else
    return c * 1.001 * (-math.pow(2, -10 * t / d) + 1) + b
  end
end

local function INOUTEXP(t, b, c, d)
  if t == 0 then return b end
  if t == d then return b + c end
  t = t / d * 2
  if t < 1 then
    return c / 2 * math.pow(2, 10 * (t - 1)) + b - c * 0.0005
  else
    t = t - 1
    return c / 2 * 1.0005 * (-math.pow(2, -10 * t) + 2) + b
  end
end

local function OUTINEXP(t, b, c, d)
  if t < d / 2 then
    return OUTEXP(t * 2, b, c / 2, d)
  else
    return INEXP((t * 2) - d, b + c / 2, c / 2, d)
  end
end

----------- CIRCULAR EASING --------
local function INCIRCULAR(t, b, c, d)
  local t = t / d
  return(-c * (math.sqrt(1 - math.pow(t, 2)) - 1) + b)
end

local function OUTCIRCULAR(t, b, c, d)
  local t = t / d - 1
  return(c * math.sqrt(1 - math.pow(t, 2)) + b)
end

local function INOUTCIRCULAR(t, b, c, d)
  local t = t / d * 2
  if t < 1 then
    return -c / 2 * (math.sqrt(1 - t * t) - 1) + b
  else
    t = t - 2
    return c / 2 * (math.sqrt(1 - t * t) + 1) + b
  end
end

local function OUTINCIRCULAR(t, b, c, d)
  if t < d / 2 then
    return OUTCIRCULAR(t * 2, b, c / 2, d)
  else
    return INCIRCULAR((t * 2) - d, b + c / 2, c / 2, d)
  end
end

----------- BOUNCE EASING --------
local function OUTBOUNCE(t, b, c, d)
  local t = t / d
  if t < 1 / 2.75 then
    return c * (7.5625 * t * t) + b
  elseif t < 2 / 2.75 then
    t = t - (1.5 / 2.75)
    return c * (7.5625 * t * t + 0.75) + b
  elseif t < 2.5 / 2.75 then
    t = t - (2.25 / 2.75)
    return c * (7.5625 * t * t + 0.9375) + b
  else
    t = t - (2.625 / 2.75)
    return c * (7.5625 * t * t + 0.984375) + b
  end
end

local function INBOUNCE(t, b, c, d)
  return c - OUTBOUNCE(d - t, 0, c, d) + b
end

local function INOUTBOUNCE(t, b, c, d)
  if t < d / 2 then
    return INBOUNCE(t * 2, 0, c, d) * 0.5 + b
  else
    return OUTBOUNCE(t * 2 - d, 0, c, d) * 0.5 + c * .5 + b
  end
end

local function OUTINBOUNCE(t, b, c, d)
  if t < d / 2 then
    return OUTBOUNCE(t * 2, b, c / 2, d)
  else
    return INBOUNCE((t * 2) - d, b + c / 2, c / 2, d)
  end
end

----------- BACK EASING --------
local function INBACK(t, b, c, d, s)
  local s = s and s or 1.70158
  local t = t / d
  return c * t * t * ((s + 1) * t - s) + b
end

local function OUTBACK(t, b, c, d, s)
  local s = s and s or 1.70158
  local t = t / d - 1
  return c * (t * t * ((s + 1) * t + s) + 1) + b
end

local function INOUTBACK(t, b, c, d, s)
  local s = s and s or 1.70158
  s = s * 1.525
  local t = t / d * 2
  if t < 1 then
    return c / 2 * (t * t * ((s + 1) * t - s)) + b
  else
    t = t - 2
    return c / 2 * (t * t * ((s + 1) * t + s) + 2) + b
  end
end

local function OUTINBACK(t, b, c, d, s)
  if t < d / 2 then
    return OUTBACK(t * 2, b, c / 2, d, s)
  else
    return INBACK((t * 2) - d, b + c / 2, c / 2, d, s)
  end
end

----------- ELASTIC EASING --------
local function INELASTIC(t, b, c, d, a, p)
  local t = t
  if t == 0 then return b end
  local t = t / d
  if t == 1  then return b + c end
  local p = p and p or d*0.3
  local s
  local a = a
  if not a or a < math.abs(c) then
    a = c
    s = p / 4
  else
    s = p / (2 * math.pi) * math.asin(c/a)
  end
  t = t - 1
  return -(a * math.pow(2, 10 * t) * math.sin((t * d - s) * (2 * math.pi) / p)) + b
end

local function OUTELASTIC(t, b, c, d, a, p)
  local t = t
  if t == 0 then return b end
  local t = t / d
  if t == 1 then return b + c end
  local p = p and p or d*0.3
  local s
  local a = a
  if not a or a < math.abs(c) then
    a = c
    s = p / 4
  else
    s = p / (2 * pi) * math.asin(c/a)
  end
  return a * math.pow(2, -10 * t) * math.sin((t * d - s) * (2 * math.pi) / p) + c + b
end


local function INOUTELASTIC(t, b, c, d, a, p)
  local t = t
  if t == 0 then return b end
  local t = t / d * 2
  if t == 2 then return b + c end
  local p = p and p or d*0.3*1.5
  local a  = a and a or 0
  local s
  if not a or a < math.abs(c) then
    a = c
    s = p / 4
  else
    s = p / (2 * math.pi) * math.asin(c / a)
  end

  if t < 1 then
    t = t - 1
    return -0.5 * (a * math.pow(2, 10 * t) * math.sin((t * d - s) * (2 * math.pi) / p)) + b
  else
    t = t - 1
    return a * math.pow(2, -10 * t) * math.sin((t * d - s) * (2 * math.pi) / p ) * 0.5 + c + b
  end
end


local function OUTINELASTIC(t, b, c, d, a, p)
  if t < d / 2 then
    return OUTELASTIC(t * 2, b, c / 2, d, a, p)
  else
    return INELASTIC((t * 2) - d, b + c / 2, c / 2, d, a, p)
  end
end

-- Returns all easing effets
return {
		LINEAR = LINEAR,          INQUART = INQUART,          INSINE = INSINE,        INCIRCULAR = INCIRCULAR, 		  INBACK = INBACK,
		INQUAD = INQUAD,          OUTQUART = OUTQUART,        OUTSINE = OUTSINE,      OUTCIRCULAR = OUTCIRCULAR,      OUTBACK = OUTBACK,
		OUTQUAD = OUTQUAD,        OUTINQUART = OUTINQUART,    OUTINSINE = OUTINSINE,  OUTINCIRCULAR = OUTINCIRCULAR,  OUTINBACK = OUTINBACK,
		INOUTQUAD = INOUTQUAD,    INOUTQUUART = INOUTQUUART,  INOUTSINE = INOUTSINE,  INOUTCIRCULAR = INOUTCIRCULAR,  INOUTBACK = INOUTBACK,
		INCUBIC = INCUBIC,        INQUINT = INQUINT,          INEXP = INEXP,          INBOUNCE = INBOUNCE,            INELASTIC = INELASTIC,
		OUTCUBIC = OUTCUBIC, 	  OUTQUINT = OUTQUINT,        OUTEXP = OUTEXP,        OUTBOUNCE = OUTBOUNCE,          OUTELASTIC = OUTELASTIC,
		OUTINCUBIC = OUTINCUBIC,  OUTINQUINT = OUTINQUINT,    OUTINEXP = OUTINEXP,    OUTINBOUNCE = OUTINBOUNCE,      OUTINELASTIC = OUTINELASTIC,
		INOUTCUBIC = INOUTCUBIC,  INOUTQUINT = INOUTQUINT,    INOUTEXP = INOUTEXP,    INOUTBOUNCE = INOUTBOUNCE,      INOUTELASTIC = INOUTELASTIC,
		}

